﻿using JoyAdmin.Core;
using Furion;
using Furion.DatabaseAccessor;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Linq;
using System.Linq.Expressions;

namespace JoyAdmin.EntityFramework.Core
{
    [AppDbContext("SqliteConnectionString")]
    public class DefaultDbContext : AppDbContext<DefaultDbContext>, IMultiTenantOnTable, IModelBuilderFilter

    {
        public DefaultDbContext(DbContextOptions<DefaultDbContext> options) : base(options)
        {
             EnabledEntityStateTracked= false;
        }
        public object GetTenantId()
        {
            // 判断 HttpContext 是否存在
            var httpContextAccessor = App.GetService<IHttpContextAccessor>();
            if (httpContextAccessor == null || httpContextAccessor.HttpContext == null) return default;

            // 获取主机地址
            var host = httpContextAccessor.HttpContext.Request.Host.Value;

            // 从内存缓存中读取或查询数据库
            var memoryCache = App.GetService<IMemoryCache>();
            var sysTenant = memoryCache.Get<SysTenant>($"{host}:MultiTenants");

            if (sysTenant == null)
            {
                var tenantDbContext = Db.GetDbContext<MultiTenantDbContextLocator>();
                if (tenantDbContext == null)
                {
                    return default;
                }
                sysTenant = tenantDbContext.Set<SysTenant>().FirstOrDefault(u => u.Host == host);
            }
            if (sysTenant == null)
            {
                return default;
            }
            else
            {
                return sysTenant.TenantId;
            } 
        } 
        
        public void OnCreating(ModelBuilder modelBuilder, EntityTypeBuilder entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
            entityBuilder.HasQueryFilter(TenantIdQueryFilterExpression(entityBuilder, dbContext));
        }
        protected override void SavingChangesEvent(DbContextEventData eventData, InterceptionResult<int> result)
        {
            // 获取当前事件对应上下文
            var dbContext = eventData.Context;

            // 获取所有新增和更新的实体
            var entities = dbContext.ChangeTracker.Entries().Where(u => u.State == EntityState.Added || u.State == EntityState.Modified || u.State == EntityState.Deleted);
            var authorizationManager = App.GetService<IAuthorizationManager>();
            var userId = 0L;
            var userName = "";
            if (authorizationManager.CheckToken())
            {
                userId = authorizationManager.GetUserId();
                userName = authorizationManager.GetUserName();
            } 
            foreach (var entity in entities)
            {
                if (entity.Entity is UserRole or RoleSecurity)
                {
                    return;
                }
                switch (entity.State)
                {
                    // 新增
                    case EntityState.Added:
                        entity.Property(nameof(BusEntity.UpdatedTime)).IsModified = false;
                        entity.Property(nameof(BusEntity.UpdatedUserId)).IsModified = false;
                        entity.Property(nameof(BusEntity.UpdatedUser)).IsModified = false;
                        entity.Property(nameof(BusEntity.CreatedTime)).CurrentValue = DateTimeOffset.UtcNow;
                        entity.Property(nameof(BusEntity.CreatedUserId)).CurrentValue = userId;
                        entity.Property(nameof(BusEntity.CreatedUser)).CurrentValue = userName;
                        entity.Property(nameof(BusEntity.TenantId)).CurrentValue = GetTenantId();
                        break;
                    // 修改
                    case EntityState.Modified:
                        entity.Property(nameof(BusEntity.CreatedTime)).IsModified = false;
                        entity.Property(nameof(BusEntity.CreatedUserId)).IsModified = false;
                        entity.Property(nameof(BusEntity.CreatedUser)).IsModified = false; 
                        entity.Property(nameof(BusEntity.UpdatedTime)).CurrentValue = DateTimeOffset.UtcNow;
                        entity.Property(nameof(BusEntity.UpdatedUserId)).CurrentValue = userId;
                        entity.Property(nameof(BusEntity.UpdatedUser)).CurrentValue = userName;
                        entity.Property(nameof(Entity.TenantId)).IsModified = false;
                        break;
                } 
        }
        }
        
        /// <summary>
        /// 构建 u => EF.Property<bool>(u,"IsDeleted") == false 表达式
        /// </summary>
        /// <param name="build"></param>
        /// <returns></returns>
        private LambdaExpression BuildIsDeleteLambdaExpression(EntityTypeBuilder build)
        {
            var mateData = build.Metadata;
            if (mateData.FindProperty(nameof(Entity.IsDeleted)) == null) return default;

            var parameter = Expression.Parameter(mateData.ClrType, "u");
            var propertyName = Expression.Constant(nameof(Entity.IsDeleted));
            var propertyValue = Expression.Constant(false);

            var expressionBody = Expression.Equal(Expression.Call(typeof(EF), nameof(EF.Property), new[] { typeof(bool) }, parameter, propertyName), propertyValue);
            var expression = Expression.Lambda(expressionBody, parameter);
            return expression;

        }
    }
}